
// ===============================================================================================================
// -*- C++ -*-
//
// GeoUtils.cpp - Geometry tools and utilities.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#include <GeoUtils.hpp>

GLuint CreateDisplayList(const Vertex vertices[], int numVerts, const Triangle triangles[], int NumTris)
{
	GLuint displayID = glGenLists(1);

	glNewList(displayID, GL_COMPILE);

	for (int i = 0; i < NumTris; ++i)
	{
		const Triangle & Tri = triangles[i];

		glBegin(GL_TRIANGLES);

		glTexCoord2fv(vertices[Tri.vertices[0]].st);
		glNormal3fv(vertices[Tri.vertices[0]].normal.v);
		glVertex3fv(vertices[Tri.vertices[0]].position.v);

		glTexCoord2fv(vertices[Tri.vertices[1]].st);
		glNormal3fv(vertices[Tri.vertices[1]].normal.v);
		glVertex3fv(vertices[Tri.vertices[1]].position.v);

		glTexCoord2fv(vertices[Tri.vertices[2]].st);
		glNormal3fv(vertices[Tri.vertices[2]].normal.v);
		glVertex3fv(vertices[Tri.vertices[2]].position.v);

		glEnd();
	}

	glEndList();

	return (displayID);
}

void Create3DBox(Vertex vertices[24], Triangle triangles[12], float width, float height, float depth)
{
	// Precomputed box data:

	static const unsigned short boxFaces[6][4] =
	{
		{ 0, 1, 5, 4 }, { 4, 5, 6, 7 }, { 7, 6, 2, 3 },
		{ 1, 0, 3, 2 }, { 1, 2, 6, 5 }, { 0, 4, 7, 3 }
	};

	static const float boxVertices[8][3] =
	{
		{-0.5f, -0.5f, -0.5f},
		{-0.5f, -0.5f,  0.5f},
		{ 0.5f, -0.5f,  0.5f},
		{ 0.5f, -0.5f, -0.5f},

		{-0.5f, 0.5f, -0.5f},
		{-0.5f, 0.5f,  0.5f},
		{ 0.5f, 0.5f,  0.5f},
		{ 0.5f, 0.5f, -0.5f},
	};

	static const float boxNormals[6][3] =
	{
		{-1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f, 0.0f},
		{0.0f, -1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, -1.0f}
	};

	static const float boxTexCoords[4][2] =
	{
		{0.0f, 0.0f},
		{1.0f, 0.0f},
		{1.0f, 1.0f},
		{0.0f, 1.0f}
	};

	// Fill in the user structs:

	unsigned short n = 0;
	Vertex * v = vertices;
	Triangle * t = triangles;

	// 'i' Iterates over the faces, 2 triangles per face:

	for (int i = 0; i < 6; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			v->position.x = boxVertices[boxFaces[i][j]][0] * width;
			v->position.y = boxVertices[boxFaces[i][j]][1] * height;
			v->position.z = boxVertices[boxFaces[i][j]][2] * depth;

			v->normal.x = boxNormals[i][0];
			v->normal.y = boxNormals[i][1];
			v->normal.z = boxNormals[i][2];

			v->st[0] = boxTexCoords[j][0];
			v->st[1] = boxTexCoords[j][1];

			++v;
		}

		t->vertices[0] = (n);
		t->vertices[1] = (n + 1);
		t->vertices[2] = (n + 2);
		++t;

		t->vertices[0] = (n + 2);
		t->vertices[1] = (n + 3);
		t->vertices[2] = (n);
		++t;

		n += 4;
	}
}

bool BoundingBoxFromPoints(const Vec3 * points, int numPoints, BoundingBox * box)
{
	if ((!points) || (!box) || (numPoints <= 0))
	{
		return (false);
	}

	for (int i = 0; i < numPoints; ++i)
	{
		const Vec3 & pt = points[i];

		// Compute min extents:
		if (box->min.x > pt.x) box->min.x = pt.x;
		if (box->min.y > pt.y) box->min.y = pt.y;
		if (box->min.z > pt.z) box->min.z = pt.z;

		// Compute max extents:
		if (box->max.x < pt.x) box->max.x = pt.x;
		if (box->max.y < pt.y) box->max.y = pt.y;
		if (box->max.z < pt.z) box->max.z = pt.z;
	}

	return (true);
}

bool BoundingBoxCollision(const BoundingBox & box, const Vec3 & point)
{
	return ((point.x <= box.max.x) && (point.x >= box.min.x) &&
			(point.y <= box.max.y) && (point.y >= box.min.y) &&
			(point.z <= box.max.z) && (point.z >= box.min.z));
}

bool BoundingBoxCollision(const BoundingBox & box1, const Vec3 & box1Pos, const BoundingBox & box2, const Vec3 & box2Pos)
{
	for (int i = 0; i < 3; ++i)
	{
		if (((box1.min.v[i] + box1Pos.v[i]) > (box2.max.v[i] + box2Pos.v[i]))
		||  ((box1.max.v[i] + box1Pos.v[i]) < (box2.min.v[i] + box2Pos.v[i])))
		return (false);
	}

	return (true);
}